# !/usr/bin/env python
# -*- coding:utf-8 -*-

'''
本脚本实现以下功能：
1：采集所属服务器的基本信息（ip、hostname、os、kernel_version、cmd 等）
2: 按照标准化的端口，监测服务器安装的中间件
3：监测中间件心跳服务，定义标准化ModelData 到服务端
4: 输出标准日志
5：监控本地端口,并与服务器关联
'''
__author__='joy'

import  os,sys,platform,socket
import ConfigParser
from collections import namedtuple
import datetime
import json
import socket
#需pip安装
import pymysql.cursors
import requests

disk_ntuple = namedtuple('partition',  'device mountpoint fstype')
usage_ntuple = namedtuple('usage',  'total used free percent')
server_info = { }
''' 1、通过socket 获取本机IP'''
def getIpAndHost():
    this_hostname = socket.getfqdn(socket.gethostname())
    this_ip = socket.gethostbyname(this_hostname)
    server_info['ip'] = this_ip
    server_info['hostname'] = this_hostname

''' 2、获取Linux系统的版本信息 '''
def getOsVersion():
    osver = platform.system()
    server_info['os'] = osver

''' 3、获取系统内核版本 '''
def getKernelVersion():
    kernel_version = platform.release()
    server_info['kernel_version'] = kernel_version

''' 4、获取CPU的核心数 '''
def getCpu():
    num = 0
    with open('/proc/cpuinfo') as fd:
        for line in fd:
            if line.startswith('processor'):
                num += 1
            if line.startswith('model name'):
                cpu_model = line.split(':')[1].strip().split()
                cpu_model = cpu_model[0] + ' ' + cpu_model[2] + ' ' + cpu_model[-1]
    server_info['cpu_cores'] = num

''' 5、获取Linux系统的总物理内存 '''
def getMemory():
    with open('/proc/meminfo') as fd:
        for line in fd:
            if line.startswith('MemTotal'):
                mem = int(line.split()[1].strip())
                break
    mem = '%.f' % (mem / 1024.0)
    server_info['ram_total'] = mem

''' 6、获取硬盘大小 '''

#获取所有磁盘
def disk_partitions(all=True):

    phydevs = []
    f = open("/proc/filesystems", "r")
    for line in f:
        if not line.startswith("nodev"):
            phydevs.append(line.strip())

    retlist = []
    f = open('/etc/mtab', "r")
    for line in f:
        if not all and line.startswith('none'):
            continue
        fields = line.split()
        device = fields[0]
        mountpoint = fields[1]
        fstype = fields[2]
        if not all and fstype not in phydevs:
            continue
        if device == 'none':
            device = ''
        ntuple = disk_ntuple(device, mountpoint, fstype)
        retlist.append(ntuple)
    return retlist

#统计某磁盘使用情况，返回对象
def disk_usage(path):
    st = os.statvfs(path)
    free = (st.f_bavail * st.f_frsize)
    total = (st.f_blocks * st.f_frsize)
    used = (st.f_blocks - st.f_bfree) * st.f_frsize
    try:
        percent = ret = (float(used) / total) * 100
    except ZeroDivisionError:
        percent = 0
    return usage_ntuple(total, used, free, round(percent, 1))

# 获取磁盘分区
def getPath():
    disklist = []
    list = disk_partitions()
    for i in list:
        disklist.append(i[1])
    return disklist
# 获取磁盘总大小
def getDiskTotal():
    newpathlist = []
    pathlist = []
    pathlist = getPath()
    pathlist.append("/dev/shm/")
    totalDiskList = []
    sum = 0
    for path in pathlist:
        disktotal = disk_usage(path)[0] / 1073741824 + 1
        totalDiskList.append(disktotal)
    for count in totalDiskList:
        sum += count
    server_info['disk_total'] = sum
''' 99.初始化Mysql数据库 '''
def initConnect():
    #获取脚本当前路径
    root_dir = os.path.dirname(os.path.abspath('.'))
    cf = ConfigParser.ConfigParser()
    cf.read('server_agent.conf')

    sections = cf.sections()
    db_host = cf.get('mysql','db_host')
    db_port = cf.get('mysql', 'db_port')
    db_user = cf.get('mysql', 'db_user')
    db_pass = cf.get('mysql', 'db_pass')
    db_name = cf.get('mysql', 'db_name')
    db_charset = cf.get('mysql', 'db_charset')
    db_connect = pymysql.connect(db_host, db_user, db_pass, db_name)
    return db_connect

#执行终端SQL插入
def toExecuteEndPointsSQL():
    # 获取当前时间
    nowtime = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    connect = initConnect()
    try:
        # 获取游标
        cursor = connect.cursor()
        # 查询是否存在，若存在更新心跳时间
        selSQL = "select count(1) from monitor_endpoints where ip =  '%s' " % (server_info.get('ip'))
        cursor.execute(selSQL)
        selResult = cursor.fetchone()
        if selResult[0] > 0:
            upSQL = "update monitor_endpoints set update_time = '%s'  where ip = '%s' " % (nowtime , server_info.get('ip'))
            cursor.execute(upSQL)
            connect.commit()
        else:
            insertSQL = " INSERT INTO monitor_endpoints   (ip , hostname , os , kernel_version , cpu_cores , \
                 ram_total , disk_total ,is_monitor ,create_time ,update_time ) VALUES  ('%s' ,'%s' , '%s' , '%s' , '%s', '%s', '%s' , 1 , '%s', '%s' )" % \
                        (server_info.get('ip'), server_info.get('hostname'), server_info.get('os'), \
                         server_info.get('kernel_version'), server_info.get('cpu_cores'), server_info.get('ram_total'), \
                         server_info.get('disk_total'), nowtime, nowtime)
            dbresult = cursor.execute(insertSQL)
            if dbresult:
                print '执行成功'
                connect.commit()
            else:
                print '执行失败'
    except Exception  as e:
        print "Exception info : \t", str(e)
        connect.rollback()
    finally:
        connect.close()

#执行中间件SQL插入
def toExecuteCenterSQL():
    # 获取当前时间
    nowtime = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    #获取存活的中间件列表
    exist_center_list = monitor_port()
    connect = initConnect()
    try:
        # 获取游标
        cursor = connect.cursor()
        for center in exist_center_list:
            # 查询是否存在，若存在更新心跳时间
            selSQL = "select count(1) from monitor_center where ip =  '%s'  and  center_name = '%s' " % (server_info.get('ip') ,center[0])
            cursor.execute(selSQL)
            selResult = cursor.fetchone()
            if selResult[0] > 0:
                upSQL = "update monitor_center set update_time = '%s'  where ip = '%s'  and center_name = '%s' " % (
                nowtime, server_info.get('ip') ,center[0])
                cursor.execute(upSQL)
                connect.commit()
            else:
                insertSQL = " INSERT INTO monitor_center   (ip , hostname , center_name , center_port , \
                     create_time ,update_time ) VALUES  ('%s' ,'%s' , '%s' , '%s' , '%s', '%s' )" % \
                            (server_info.get('ip'), server_info.get('hostname'), center[0] , \
                             center[1], nowtime, nowtime)
                dbresult = cursor.execute(insertSQL)
                if dbresult:
                    print '执行成功'
                    connect.commit()
                else:
                    print '执行失败'
    except Exception as e:
        print '执行中间件SQL异常'
    finally:
        connect.close()

#监测端口存活,返回存活列表
def monitor_port():
    root_dir = os.path.dirname(os.path.abspath('.'))
    cf = ConfigParser.ConfigParser()
    # 读取配置文件
    cf.read('server_agent.conf')
    center_list = cf.items('center_list')
    # 存在的中间件列表
    exist_center_list = []
    for center in center_list:
        try:
            sc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sc.settimeout(2)
            connectResult = sc.connect(('127.0.0.1', int(center[1])))
            print '中间件：', center[0], ' 端口：', str(center[1]), '连接成功！'
            exist_center_list.append(center)
            sc.close()
        except Exception as e:
            print str(e)
            print '中间件：', center[0], ' 端口：', str(center[1]), '连接失败！'
    return  exist_center_list

''' 100.执行测试 '''
if __name__ == '__main__':
    getIpAndHost()
    getOsVersion()
    getKernelVersion()
    getCpu()
    getMemory()
    getDiskTotal()

    root_dir = os.path.dirname(os.path.abspath('.'))
    cf = ConfigParser.ConfigParser()
    # 读取配置文件
    cf.read('server_agent.conf')
    toMysql = cf.get('init', 'toMysql')
    if toMysql == 'True' :
        print '操作数据库'
        toExecuteEndPointsSQL()
        toExecuteCenterSQL()
    else:
        print '调用HTTP接口'
        jsonObj = json.dumps(server_info)
        print jsonObj
        json_Obj_prefect = json.dumps(jsonObj, sort_keys=True, indent=4, separators=(',', ': '))
        print json_Obj_prefect
        push_server = cf.get('server', 'push_server')
        token_headers = {'content-type': "application/json", 'Authorization': 'APP appid = 4abf1a,token = 9480295ab2e2eddb8'}
        headers = {'content-type': "application/json"}
        response = requests.post(push_server, data=jsonObj, headers=headers)
        # 返回信息
        print response.text
        # 返回响应头
        print response.status_code




